package vesion2.main;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import vesion2.barrier.*;
import vesion2.barrier.spec.BornFactory;
import vesion2.barrier.spec.BornPlace;
import vesion2.barrier.spec.Crass;
import vesion2.tank.Bullet;
import vesion2.object.Point;
import vesion2.tank.EnemyTank;
import vesion2.tank.MyTank;
import vesion2.tool.*;

import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.util.ArrayList;
import java.util.Vector;

/**
 * gamePanel 主要对象的管理类
 */
public class ObjectManager{
    //容器
    GamePanel gamePanel;
    //已经击杀的敌人
    private int hasKillNum=0;
    //死亡次数
    private int deathNum=0;

    private int allank=8;
    private int maxTank=8;
    //自己的坦克
    private MyTank myTank;
    //敌人坦克
    private Vector<EnemyTank> enemyTanks = new Vector<>();
    //子弹集
    private Vector<Bullet> bullets=new Vector<>();
    //爆炸集
    private Vector<Bomb> bombs=new Vector<>();
    //障碍物集合
    private Vector<Barrier> barriers=new Vector<>();
    //帅
    private Brick King;

    private ArrayList<Crass> crassArrayList;

    private ArrayList<BornPlace> bornPlaces;

    private ObjectSave objectSave;

    private Thread crateEnemy;

    public ObjectManager(GamePanel panel){
        gamePanel=panel;
        objectSave=new ObjectSave();
        King=new Brick(new Point(410,610),80,80);
    }

    public void InitData(){
        initKing();
        objectSave.loadDefaultObject();
        for (BornPlace place : bornPlaces) {
            place.addHome(barriers);
            if (place.getType() == 0) {
                myTank = new MyTank(place.getTankPoint(), 4);
                myTank.setManager(this);
                myTank.setPlace(place);
            }
            place.setTanks(enemyTanks);
        }
        myTank.setManager(this);
    }

    public boolean loadPre(){
        if(objectSave.loadPreGame("src\\main\\resources\\pre.json"))
        {
            King.setImage(LoadImages.getImageInPath("/king.png"));
            barriers.add(King);
            crassArrayList= objectSave.getCrasses();
            bornPlaces=objectSave.getBornPlaces();
            for(BornPlace place:bornPlaces) {
                place.addHome(barriers);
                place.setTanks(enemyTanks);
            }
            myTank.setManager(this);
            for(EnemyTank ee:enemyTanks)
                ee.setManager(this);
            return true;
        }
        return false;
    }

    public boolean loadNew(String filePath){
        if(filePath==null||filePath=="")
            return false;
        if(objectSave.loadMapFromJson(filePath))
        {
            initKing();
            crassArrayList = objectSave.getCrasses();
            bornPlaces = objectSave.getBornPlaces();
            for (BornPlace place : bornPlaces) {
                place.addHome(barriers);
                if (place.getType() == 0) {
                    myTank = new MyTank(place.getTankPoint(), 4);
                    myTank.setManager(this);
                    myTank.setPlace(place);
                }
                place.setTanks(enemyTanks);
            }
            myTank.setManager(this);
            return true;
        }
        return false;
    }

    public  void clear(){
        barriers.clear();
        for(int i=0;i<enemyTanks.size();i++)
        {
            EnemyTank enemyTank = enemyTanks.get(i);
            enemyTank.setAlive(false);
        }
        enemyTanks.clear();
        hasKillNum=0;
        deathNum=0;
    }

    public void createEnemyTank(){
        if(crateEnemy==null||!crateEnemy.isAlive()) {
            crateEnemy = new Thread(() -> {
                while (allank > enemyTanks.size() + hasKillNum&&!gamePanel.isStop()) {
                    for (BornPlace bp : bornPlaces)
                        if (bp.getType() == 1 && enemyTanks.size() < maxTank && bp.canUse()) {
                            EnemyTank enemyTank = new EnemyTank(bp.getTankPoint());
                            enemyTank.setManager(this);
                            enemyTanks.add(enemyTank);
                            enemyTank.start();
                        }

                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
            );
            crateEnemy.start();
        }
    }


    private void initKing(){
        King=new Brick(new Point(410,610),80,80);
        King.setImage(LoadImages.getImageInPath("/king.png"));
        barriers.add(King);
        //上
        barriers.add(new Brick(new Point(390,590),20,20));
        barriers.add(new Brick(new Point(410,590),20,20));
        barriers.add(new Brick(new Point(430,590),20,20));
        barriers.add(new Brick(new Point(450,590),20,20));
        barriers.add(new Brick(new Point(470,590),20,20));
        barriers.add(new Brick(new Point(490,590),20,20));
        //左
        barriers.add(new Brick(new Point(390,610),20,20));
        barriers.add(new Brick(new Point(390,630),20,20));
        barriers.add(new Brick(new Point(390,650),20,20));
        barriers.add(new Brick(new Point(390,670),20,20));

        //右
        barriers.add(new Brick(new Point(490,610),20,20));
        barriers.add(new Brick(new Point(490,630),20,20));
        barriers.add(new Brick(new Point(490,650),20,20));
        barriers.add(new Brick(new Point(490,670),20,20));
    }

    public void saveGame(){
        objectSave.refresh();
        objectSave.saveGame("src\\main\\resources\\pre.json");
    }

    public void saveMap(){
        objectSave.saveMapToJson("src\\main\\resources\\map1.json");
    }

    public MyTank getMyTank() {
        return myTank;
    }

    public void setMyTank(MyTank myTank) {
        this.myTank = myTank;
    }

    public Vector<Barrier> getBarriers() {
        return barriers;
    }

    public Vector<EnemyTank> getEnemyTanks() {
        return enemyTanks;
    }

    public Vector<Bullet> getBullets() {
        return bullets;
    }

    public Vector<Bomb> getBombs() {
        return bombs;
    }

    public void addEnemyTank(EnemyTank tank){
        enemyTanks.add(tank);
    }

    public void setHasKillNum(int hasKillNum) {
        this.hasKillNum = hasKillNum;
    }

    public void setDeathNum(int deathNum) {
        this.deathNum = deathNum;
    }

    public void setAllank(int allank) {
        this.allank = allank;
    }

    public void setMaxTank(int maxTank) {
        this.maxTank = maxTank;
    }

    public int getAllank() {
        return allank;
    }

    public int getMaxTank() {
        return maxTank;
    }

    public void addBomb(Bomb bomb){
        bombs.add(bomb);
    }

    public void addBullet(Bullet bullet){
        bullets.add(bullet);
    }

    public GamePanel getGamePanel() {
        return gamePanel;
    }

    public void setGamePanel(GamePanel gamePanel) {
        this.gamePanel = gamePanel;
    }

    public void draw(Graphics g){
        if(!King.isAlive())
            showDia("失败了");
        if(hasKillNum==allank)
            showDia("成功了");
        if(myTank!=null){
            if(myTank.isAlive()) {
                g.setColor(myTank.getBackColor());
                myTank.draw(g);
            }
            else
                myTank.setAlive(true);
        }
        for(int i=0;i<barriers.size();i++){
            Barrier barrier = barriers.get(i);
            if (barrier.isAlive()) {
                if (barrier.getImage() != null)
                    barrier.drawImage(g, gamePanel);
                else
                    barrier.draw(g);
            }
            else
                barriers.remove(i);
        }
        for(int i=0;i<enemyTanks.size();i++)
        {
            EnemyTank enemyTank = enemyTanks.get(i);
            if(enemyTank.isAlive())
                enemyTank.draw(g);
            else
                enemyTanks.remove(i);
        }
        for (int i=0;i<bullets.size();i++)
        {
            Bullet bullet = bullets.get(i);
            if(bullet.isAlive())
                bullet.draw(g);
            else
                bullets.remove(i);
        }

        for(int i=0;i<bombs.size();i++)
        {
            Bomb bomb = bombs.get(i);
            if(bomb.isAlive())
                bomb.draw(g,gamePanel);
            else
                bombs.remove(i);
        }

        for (Crass crass:crassArrayList)
            crass.draw(g);
    }

    private boolean hasShow=false;
    public void showDia(String mess){
        if(!hasShow) {
            hasShow=true;
            JOptionPane.showMessageDialog(null, mess);
        }
    }
    public int getHasKillNum() {
        return hasKillNum;
    }

    public int getDeathNum() {
        return deathNum;
    }

    public synchronized void incKNum(){
        ++hasKillNum;
    }

    public synchronized void incDNUm(){++deathNum;}

    class ObjectSave{
        private Barriers myBarriers;
        private ArrayList<Crass> crasses;
        private ArrayList<BornPlace> bPlaces;

        public ObjectSave(){
            myBarriers=new Barriers();
            crasses=new ArrayList<>();
            bPlaces=new ArrayList<>();
        }

        public void loadDefaultObject(){
            clear();
            loadDefaultBarrier();
            loadDefaultCrasses();
            loadDefaultBornPlace();
            crassArrayList = crasses;
            bornPlaces =bPlaces;
           addToBarriers(barriers);
        }

        /**
         * 加载自带的地图障碍物
         */
        public void loadDefaultBarrier(){
            ArrayList<Brick> bricks = myBarriers.getBricks();
            ArrayList<Iron> irons = myBarriers.getIrons();
            ArrayList<Water> waters = myBarriers.getWaters();
            LoadDefaultData.initDIron(irons,new Point(300,10),30,120);
            LoadDefaultData.initDIron(irons,new Point(190,10),110,30);
            LoadDefaultData.initDIron(irons,new Point(240,40),60,60);


            LoadDefaultData.initFDBrick(bricks,new Point(100,100));
            LoadDefaultData.initFDBrick(bricks,new Point(180,180));

            LoadDefaultData.initFDBrick(bricks,new Point(10,300));
            LoadDefaultData.initFDBrick(bricks,new Point(90,300));
            LoadDefaultData.initFDBrick(bricks,new Point(250,300));
            LoadDefaultData.initFDBrick(bricks,new Point(330,300));
            LoadDefaultData.initFBrick(bricks,new Point(410,300));

            LoadDefaultData.initDWater(waters,new Point(10,380),90,80);

            LoadDefaultData.initFDBrick(bricks,new Point(10,460));
            LoadDefaultData.initFDBrick(bricks,new Point(90,460));
            LoadDefaultData.initFDBrick(bricks,new Point(170,460));
            LoadDefaultData.initFDBrick(bricks,new Point(250,460));
            LoadDefaultData.initFDBrick(bricks,new Point(330,460));
            LoadDefaultData.initBrick(bricks,new Point(410,460));
        }

        /**
         * 加载自带的地图草丛
         */
        public void loadDefaultCrasses(){
            crasses.add(new Crass(new Point(100,380),700,80));
        }

        /**
         * 加载自带的出生地
         */
        public void loadDefaultBornPlace(){
            bPlaces.add(BornFactory.createBorn(new Point(10,10),1));
            bPlaces.add(BornFactory.createBorn(new Point(400,10),1));
            bPlaces.add(BornFactory.createBorn(new Point(800,10),1));
            bPlaces.add(BornFactory.createBorn(new Point(600,600),0));
        }

        /**
         * 向 manager中barriers添加障碍物
         * @param barriers
         */
        public void addToBarriers(Vector<Barrier> barriers){
            for(Brick bk:myBarriers.getBricks())
                barriers.add(bk);
            for(Water bk:myBarriers.getWaters())
                barriers.add(bk);
            for(ProtectLimit bk:myBarriers.getProtectLimits())
                barriers.add(bk);
            for(Iron bk:myBarriers.getIrons())
                barriers.add(bk);
        }

        private void refresh(){
            ArrayList<Brick> bricks = new ArrayList<>();
            for(Barrier barr:barriers)
                if((barr instanceof Brick)&&barr.isAlive())
                    bricks.add((Brick) barr);
                myBarriers.setBricks(bricks);
        }

        private void clear(){
            crasses.clear();
            bPlaces.clear();
            myBarriers.clear();
        }
        //---->持久化json和读取<----//

        public boolean loadMapFromJson(String filePath){
            clear();
            ObjectMapper mapper= new ObjectMapper();
            boolean isOk=true;
            JsonNode jsonNode=null;
            try {
                File file=new File(filePath);
                jsonNode= mapper.readTree(file);
                JsonNode bjsnoed= jsonNode.path("barriers");
                JsonNode cjsnode = jsonNode.path("crass");
                JsonNode bornjsoned = jsonNode.path("born");

                myBarriers= JsonUtils.jsonToPojo(bjsnoed.toString(), Barriers.class);
                crasses = (ArrayList<Crass>) JsonUtils.jsonToList(cjsnode.toString(), Crass.class);
                bPlaces=(ArrayList<BornPlace>)JsonUtils.jsonToList(bornjsoned.toString(),BornPlace.class);
            } catch (IOException e) {
                e.printStackTrace();
                isOk=false;
            }
            crassArrayList = crasses;
            bornPlaces =bPlaces;
            addToBarriers(barriers);
            return isOk;
        }

        public void saveMapToJson(String filePath){
            BufferedWriter bw=null;
            try {
                bw=new BufferedWriter(new FileWriter(filePath));
                String bar=JsonUtils.objectToJson(myBarriers);
                String cra=JsonUtils.objectToJson(crasses);
                String bor=JsonUtils.objectToJson(bPlaces);
                String json="{\"barriers\":"+bar+",\"crass\":"+cra+",\"born\":"+bor+"}";
                bw.write(json);
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                if(bw!=null) {
                    try {
                        bw.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }

        public void saveGame(String filePath){
            refresh();
            BufferedWriter bw=null;
            try {
                bw=new BufferedWriter(new FileWriter(filePath));
                String bar=JsonUtils.objectToJson(myBarriers);
                String cra=JsonUtils.objectToJson(crasses);
                String bor=JsonUtils.objectToJson(bPlaces);
                String mttk=JsonUtils.objectToJson(myTank);
                String ents=JsonUtils.objectToJson(enemyTanks);
                String json="{\"kill\":"+hasKillNum+",\"death\":"+deathNum+",\"max\":"+maxTank+",\"all\":"+allank+"," +
                        "\"mytank\":"+mttk+",\"enemy\":"+ents+",\"barriers\":"+bar+",\"crass\":"+cra+",\"born\":"+bor+"}";
                bw.write(json);
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                if(bw!=null) {
                    try {
                        bw.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }

        public boolean loadPreGame(String filePath){
            clear();
            ObjectMapper mapper= new ObjectMapper();
            File file=new File(filePath);
            if(!file.exists())
                return false;
            JsonNode jsonNode=null;
            try {
                jsonNode= mapper.readTree(file);
                hasKillNum=jsonNode.get("kill").intValue();
                deathNum=jsonNode.get("death").intValue();
                maxTank=jsonNode.get("max").intValue();
                allank=jsonNode.get("all").intValue();
                JsonNode mjsnod=jsonNode.path("mytank");
                JsonNode enjsond=jsonNode.path("enemy");
                JsonNode bjsnoed= jsonNode.path("barriers");
                JsonNode cjsnode = jsonNode.path("crass");
                JsonNode bornjsoned = jsonNode.path("born");
                myBarriers= JsonUtils.jsonToPojo(bjsnoed.toString(), Barriers.class);
                crasses = (ArrayList<Crass>) JsonUtils.jsonToList(cjsnode.toString(), Crass.class);
                bPlaces=(ArrayList<BornPlace>)JsonUtils.jsonToList(bornjsoned.toString(),BornPlace.class);
                enemyTanks=new Vector<>((ArrayList<EnemyTank>)JsonUtils.jsonToList(enjsond.toString(),EnemyTank.class));
                myTank=(MyTank) JsonUtils.jsonToPojo(mjsnod.toString(),MyTank.class);
            } catch (IOException e) {
                e.printStackTrace();
            }
            crassArrayList = crasses;
            bornPlaces =bPlaces;
            addToBarriers(barriers);
            return true;
        }

        //------>以下是get和set<--------//


        public Barriers getMyBarriers() {
            return myBarriers;
        }

        public void setMyBarriers(Barriers myBarriers) {
            this.myBarriers = myBarriers;
        }


        public ArrayList<Crass> getCrasses() {
            return crasses;
        }

        public void setCrasses(ArrayList<Crass> crasses) {
            this.crasses = crasses;
        }

        public ArrayList<BornPlace> getBornPlaces() {
            return bPlaces;
        }

        public void setBornPlaces(ArrayList<BornPlace> bornPlaces) {
            this.bPlaces = bornPlaces;
        }
    }
    public static class Barriers {
        private ArrayList<Brick> bricks = new ArrayList<>();
        private ArrayList<Iron> irons = new ArrayList<>();
        private ArrayList<ProtectLimit> protectLimits = new ArrayList<>();
        private ArrayList<Water> waters = new ArrayList<>();

        public ArrayList<Brick> getBricks() {
            return bricks;
        }

        public void setBricks(ArrayList<Brick> bricks) {
            this.bricks = bricks;
        }

        public ArrayList<Iron> getIrons() {
            return irons;
        }

        public void setIrons(ArrayList<Iron> irons) {
            this.irons = irons;
        }

        public ArrayList<ProtectLimit> getProtectLimits() {
            return protectLimits;
        }

        public void setProtectLimits(ArrayList<ProtectLimit> protectLimits) {
            this.protectLimits = protectLimits;
        }

        public ArrayList<Water> getWaters() {
            return waters;
        }

        public void setWaters(ArrayList<Water> waters) {
            this.waters = waters;
        }

        public void clear(){
            bricks.clear();
            waters.clear();
            protectLimits.clear();
            irons.clear();
        }
        @Override
        public String toString() {
            return "Barriers{" +
                    "bricks=" + bricks +
                    ", irons=" + irons +
                    ", protectLimits=" + protectLimits +
                    ", waters=" + waters +
                    '}';
        }
    }
}
